package ca.cbc.gis.json;

import ca.cbc.gis.util.GISGeometryBuilder;
import ca.cbc.giscommon.util.StringUtil;
import ca.cbc.giscommon.entity.*;
import com.vividsolutions.jts.geom.Geometry;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class GeoJson {
    private Map<String, Object> geojson;

    public GeoJson() {
        geojson = new HashMap<String, Object>();
    }

    public GeoJson(String type) {
        this();
        geojson.put("type", type);
    }

    public <T> GeoJson(String type, T item) {
        this(type);
        if (item instanceof Content)
            this.parseGeometryAndProperties((Content) item);
        else if (item instanceof Shape)
            this.parseGeometryAndProperties((Shape) item);
        else if (item instanceof Event)
            this.parseGeometryAndProperties((Event) item);
        else if (item instanceof Story)
            this.parseGeometryAndProperties((Story) item);
        else if (item instanceof Tweet)
            this.parseGeometryAndProperties((Tweet) item);
    }

    private String emptyIfNotValid(long time) {
        if (time <= 0) {
            return "";
        }

        return Long.toString(time);
    }

    private String emptyIfNull(String str) {
        if (StringUtil.instance.isNullOrEmpty(str)) {
            return "";
        }

        return str;
    }

    public Map<String, Object> getGeojson() {
        return geojson;
    }

    private void parseGeometryAndProperties(Content content) {
        Source source = content.getSource();
        this.parseProperties("feedContent", content.getId(), source.getName(), source.getDescription(),
                source.getCategory(), content.getTitle(), content.getDescription(), content.getPublishDate().getTime(),
                content.getLink(), content.getZones(), content.getTheGeom(), null, source.getCbcContent());
    }

    private void parseGeometryAndProperties(Event event) {
        Source source = event.getSource();

        HashMap<String, Object> extraProps = new HashMap<String, Object>();
        extraProps.put("starttime", emptyIfNotValid(event.getStart().getTime()));
        extraProps.put("endtime", emptyIfNotValid(event.getEnd().getTime()));
        List<EventSubcategory> ets = event.getEventSubcategories();
        if (ets.size() != 0) {
            List<Map<String, Object>> subCategoryMapList = new ArrayList<Map<String, Object>>(6);
            for (EventSubcategory subCategory : ets) {
                Map<String, Object> subCategoryMap = new HashMap<String, Object>(2);
                subCategoryMap.put("label", subCategory.getSubcategory());
                subCategoryMap.put("id", subCategory.getId());
                subCategoryMapList.add(subCategoryMap);
            }
            extraProps.put("subcategories", subCategoryMapList);
        }
        this.parseProperties("event", event.getId(), source.getName(), source.getDescription(), source.getCategory(),
                event.getTitle(), event.getDescription(), event.getPublishDate().getTime(), event.getLink(),
                event.getZones(), event.getTheGeom(), extraProps, source.getCbcContent());
    }

    private void parseGeometryAndProperties(Shape shape) {
        ShapeType shapeType = shape.getShapeType();
        HashMap<String, Object> extraProps = new HashMap<String, Object>();
        if (!StringUtil.instance.isNullOrEmpty(shape.getPhone())) {
            extraProps.put("phone", shape.getPhone());
        }
        if (!StringUtil.instance.isNullOrEmpty(shape.getRouteNumber())) {
            extraProps.put("route", shape.getRouteNumber());
        }
//        Placeholder values - need to be re-evaluated afterwards
//        List<Map<String, Object>> subCategoryMapList = new ArrayList<Map<String, Object>>(6);
//        Map<String, Object> subCategoryMap = new HashMap<String, Object>(2);
//        subCategoryMap.put("label", shapeType.getType());
//        subCategoryMap.put("id", shapeType.getId());
//        subCategoryMapList.add(subCategoryMap);
//        extraProps.put("subcategories", subCategoryMapList);
        this.parseProperties("shape", shape.getId(), "", "", shapeType.getCategory(), shape.getName(),
                shape.getAddress(), 0l, "", shape.getZones(), shape.getTheGeom(), extraProps, false);
    }

    private void parseGeometryAndProperties(Story story) {
        Zone zone = story.getZone();
        List<Zone> zones = null;
       
        String source = "cbc";
        String sourceDesc = "Canadian Broadcasting Corporation";
        
        if (zone != null) {
            zones = new ArrayList<Zone>();
            zones.add(zone);
        }
        HashMap<String, Object> extraProps = new HashMap<String, Object>();
        extraProps.put("image", story.getThumbnail());
        extraProps.put("flag", story.getFlag());
        extraProps.put("lastupdatedate", emptyIfNotValid(story.getLastUpdatedDate().getTime()));

        String audioIds = story.getAudioClipIds();
        if (audioIds != null && audioIds.length() != 0)
            extraProps.put("audioclipids", audioIds.split(","));
        String videoIds = story.getVideoClipIds();
        if (videoIds != null && videoIds.length() != 0)
            extraProps.put("videoclipids", videoIds.split(","));
        
        if (!story.getCbcContent()) {
        	source = story.getStoryUrl();		// For lack of any other data for the moment.
        	sourceDesc = story.getStoryUrl();
        }
        
        this.parseProperties("eptStory", story.getId(), source,  sourceDesc, story.getCategory(),
                story.getTitle(), story.getDescription(), story.getPublishDate().getTime(), story.getStoryUrl(),
                zones, story.getTheGeom(), extraProps, story.getCbcContent());
    }

    private void parseGeometryAndProperties(Tweet tweet) {
        Source source = tweet.getSource();
        List<Zone> zones = new ArrayList<Zone>();
        zones.add(tweet.getZone());
        HashMap<String, String> metadata = new HashMap<String, String>();
        metadata.put("username", tweet.getTwitterUser().getScreenName());
        metadata.put("id", tweet.getStatusID());
        metadata.put("fullname", tweet.getTwitterUser().getUserName());
        metadata.put("iscbcaccount", Boolean.toString(tweet.getTwitterUser().isCbcAccount()));
        HashMap<String, Object> tweetObject = new HashMap<String, Object>();
        tweetObject.put("metadata", metadata);
        HashMap<String, Object> extraProps = new HashMap<String, Object>();
        extraProps.put("tweet", tweetObject);
        extraProps.put("lastupdatedate", emptyIfNotValid(tweet.getCreatedAt().getTime()));
        this.parseProperties("tweet", tweet.getId(), source.getName(), source.getDescription(), source.getCategory(),
                tweet.getText(), "", tweet.getCreatedAt().getTime(),
                "https://twitter.com/" + tweet.getTwitterUser().getScreenName(), zones, tweet.getTheGeom(), extraProps, source.getCbcContent());
    }

    private void parseProperties(String type, long id, String sourceName, String sourceDesc, Category category,
                                 String title, String desc, long pubdate, String uri, List<Zone> zones, Geometry geom,
                                 Map<String, Object> extraProps, boolean isCBCContent) {
        //properties map
        Map<String, Object> properties = new HashMap<String, Object>();

        //category map
        Map<String, Object> categoryMap = new HashMap<String, Object>(2);
        if (category != null) {
            categoryMap.put("label", category.getName());
            categoryMap.put("id", category.getId());
        }

        if (isCBCContent)
            sourceName = "cbc";
        properties.put("type", type);
        properties.put("id", type + '-' + Long.toString(id));
        properties.put("source", emptyIfNull(sourceName));
        properties.put("sourcedesc", emptyIfNull(sourceDesc));
        properties.put("category", categoryMap);
        properties.put("title", emptyIfNull(title));

        if (!StringUtil.instance.isNullOrEmpty(desc))
            properties.put("desc", desc);
        properties.put("pubdate", emptyIfNotValid(pubdate));

        if (!StringUtil.instance.isNullOrEmpty(uri))
            properties.put("uri", uri);

        if (zones != null) {
            List<Long> zoneIds = new ArrayList<Long>();
            for (Zone zone : zones) {
                zoneIds.add(zone.getId());
            }
            properties.put("zones", zoneIds);
        }

        if (extraProps != null)
            properties.putAll(extraProps);

        geojson.put("properties", properties);
        if (geom != null)
            geojson.put("geometry", GISGeometryBuilder.instance.buildGISGeometry(geom));
    }

    public void setGeojson(Map<String, Object> geojson) {
        this.geojson = geojson;
    }
}
